package com.symaster.common.test.pid;

import com.symaster.common.swing.FpsManager;

import static com.symaster.common.test.pid.Util.time;

public class TrainingShed extends PID {
    public float internalTemperature = 15; // 棚内温度
    public float externalTemperature = 15; // 棚外温度

    public float targetTemperature; // 目标温度
    public float heaterPower = 0f; // 加热器功率

    private Float startTime;
    final FpsManager fpsManager = new FpsManager();
    private final PowerUpdate powerUpdate;

    public TrainingShed() {
        this.powerUpdate = new PowerUpdate(this);
        start();
    }

    private Float lastCoolingTime;
    private Float lastHeatingTime;
    private Float timeCache;
    private Float heatingSpeed2UpdateTime;

    private float heatingSpeed = 0;
    private float heatingSpeed2 = 0;

    public float rate = 0f;

    private void start() {

        new Thread(() -> {
            while (true) {
                if (internalTemperature > externalTemperature && lastCoolingTime != null) {
                    heatingSpeed = -(0.5f / 1000f); // 每毫秒降低温度值
                    // System.out.println(heatingSpeed2);
                    // internalTemperature = Math.max(externalTemperature, internalTemperature - (time() - lastCoolingTime) * v);
                } else {
                    heatingSpeed = 0;
                }
                lastCoolingTime = time();

                { // heatingSpeed2 Update
                    if (heatingSpeed2UpdateTime != null) {
                        heatingSpeed2 = Math.max(heatingSpeed2 + (time() - heatingSpeed2UpdateTime) * heatingSpeed, 0);
                    }
                    heatingSpeed2UpdateTime = time();
                }

                if (heaterPower > 0 && lastHeatingTime != null) {
                    float v = heaterPower / 120 / 1000f; // 每毫秒提升温度值
                    heatingSpeed2 += (time() - lastHeatingTime) * v;
                }
                lastHeatingTime = time();

                if (timeCache != null) {
                    // System.out.println(heatingSpeed2);
                    // System.out.printf("%.6f%n", heatingSpeed2);
                    float speed = heatingSpeed + heatingSpeed2;
                    rate = speed * 1000;
                    internalTemperature += (time() - timeCache) * speed;
                }
                timeCache = time();

                fpsManager.paintWait(5);
            }
        }).start();
    }

    /**
     * 设定功率
     *
     * @param power 功率
     */
    @Override
    public void power(float power) {
        if (startTime == null) {
            startTime = time();
        }
        this.powerUpdate.newPower(power);
    }

    @Override
    public float difference() {
        return targetTemperature - internalTemperature;
    }

    private static class PowerUpdate {

        private float newPower = 0f;
        private float thatPower = 0f;

        private final float speed = 1;

        private final TrainingShed trainingShed;
        final FpsManager fpsManager = new FpsManager();

        public PowerUpdate(TrainingShed trainingShed) {
            this.trainingShed = trainingShed;
            start();
        }

        private Float lastUpdateTime;

        private void start() {
            new Thread(() -> {
                while (true) {

                    float fast;
                    if (lastUpdateTime != null && newPower != thatPower) {
                        float v = newPower - thatPower;
                        float v1 = speed / 1000 * (time() - lastUpdateTime);
                        if (v < 0) {
                            fast = Math.max(v, -v1);
                        } else {
                            fast = Math.min(v, v1);
                        }
                    } else {
                        fast = 0f;
                    }

                    thatPower += fast;
                    trainingShed.heaterPower = thatPower;

                    lastUpdateTime = time();
                    fpsManager.paintWait(5);
                }
            }).start();
        }

        public void newPower(float power) {
            this.newPower = Math.min(power, 1);
        }
    }
}